package com.csce.domain.entity.score.vo;

import cn.hutool.log.StaticLog;
import com.csce.domain.entity.score.ScoreExExamPlaceAllot;
import com.csce.domain.entity.score.ScoreExExamSession;
import com.doudou.core.container.ListUtil;
import com.doudou.core.container.MapUtil;
import com.doudou.core.container.SetUtil;
import com.doudou.core.lang.ObjUtil;
import com.doudou.core.str.StrUtil;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zzxjs
 * @since 2023/9/7
 * 分配完毕返回结构实体类
 * 查询排站时的结构顺序	：日期 -> 时间分段 -> 房间 -> 学员排站数据
 */
public class ExamAllotResult extends LinkedHashMap<String, Map<Long, Map<Long, List<List<ScoreExExamPlaceAllot>>>>> {

    private final Boolean isPlanStu;

    private final Set<Long> PLACE_ID_SET = SetUtil.hashSet();
    private final Set<Long> TIME_ID_SET = SetUtil.hashSet();

    private final Map<Long, Integer> MAX_INDEX = MapUtil.hashMap();

    private final Map<String, ScoreExExamSession> SESSION_MAP = MapUtil.hashMap();

    /**
     * 初始化，根据日期、时段id 分组节次
     *
     * @param sessions 节次集合
     */
    public ExamAllotResult(List<ScoreExExamSession> sessions, Boolean isPlanStu) {
        this.isPlanStu = isPlanStu;
        for (ScoreExExamSession session : sessions) {
            //先根据日期查下挂的时间分段
            MapUtil.put(this, session.getDateStr(), putTimeMapValue(session));
        }
    }

    private Map<Long, Map<Long, List<List<ScoreExExamPlaceAllot>>>> putTimeMapValue(ScoreExExamSession session) {
        String date = session.getDateStr();
        Map<Long, Map<Long, List<List<ScoreExExamPlaceAllot>>>> timeMap = getOrDefault(date, MapUtil.map(true));
        Long timeId = session.getTimeId();
        this.addTimeId(timeId);
        return MapUtil.put(timeMap, timeId, putPlaceMapValue(timeMap, session));
    }

    private Map<Long, List<List<ScoreExExamPlaceAllot>>> putPlaceMapValue(Map<Long, Map<Long, List<List<ScoreExExamPlaceAllot>>>> timeMap, ScoreExExamSession session) {
        Map<Long, List<List<ScoreExExamPlaceAllot>>> placeMap = timeMap.getOrDefault(session.getTimeId(), MapUtil.map(true));
        Long placeId = session.getExamPlaceId();
        this.addPlaceId(placeId);
        int maxIndex = getMaxIndex(placeId, session.getExamPlaceIndex());
        List<List<ScoreExExamPlaceAllot>> list = placeMap.get(placeId);
        if (ObjUtil.isNull(list)) {//如果为空，创一个和最大下标一样多元素的集合
            list = ListUtil.linkedList();
            for (int i = 0; i < maxIndex; i++) {
                list.add(ListUtil.linkedList());
            }
        } else if (list.size() < maxIndex) {//不为空，但是长度不够，添加缺少的元素
            for (int i = list.size(); i < maxIndex; i++) {
                list.add(ListUtil.linkedList());
            }
        }
        int index = session.getExamPlaceIndex() - 1;
        List<ScoreExExamPlaceAllot> placeAllots = list.get(index);
        placeAllots.addAll(parsePlaceAllotList(session));
        list.set(index, placeAllots);
        putSessionMap(session);
        return MapUtil.put(placeMap, placeId, list);
    }

    /**
     * 格式化下最终的集合，如果已经安排的学生的，将没有被安排到的数据过滤掉
     */
    private List<ScoreExExamPlaceAllot> parsePlaceAllotList(ScoreExExamSession session) {
        List<ScoreExExamPlaceAllot> list = session.getScoreExExamPlaceAllotList();
        if (this.isPlanStu) {
            list = session.getScoreExExamPlaceAllotList().stream().filter(a -> ObjUtil.isNotEmpty(a.getUserId())).collect(Collectors.toList());
        }
        return list;
    }

    /**
     * 判断当前最大的下标
     */
    private Integer getMaxIndex(Long placeId, Integer index) {
        if (MAX_INDEX.containsKey(placeId)) {//如果存在需要对比下
            Integer integer = MAX_INDEX.get(placeId);
            if (integer >= index) {
                index = integer;
            }
        }
        MAX_INDEX.put(placeId, index);
        return index;
    }

    /**
     * 方便前端修改考官和标准化病人设计
     */
    private void putSessionMap(ScoreExExamSession session) {
        try {
            String key = StrUtil.format("{}-{}-{}-{}", session.getDateStr(), session.getTimeId(), session.getExamPlaceId(), session.getExamPlaceIndex());
            ScoreExExamSession sessionCopy = new ScoreExExamSession() {{
                setId(session.getId());
                setSceneExaminer(session.getSceneExaminer());
                setCenterExaminer(session.getCenterExaminer());
                setSshExaminer(session.getSshExaminer());
                setSimulatedPatient(session.getSimulatedPatient());
            }};
            this.SESSION_MAP.put(key, sessionCopy);
        } catch (Exception e) {
            StaticLog.error(e);
        }
    }

    private void addPlaceId(Long placeId) {
        this.PLACE_ID_SET.add(placeId);
    }

    private void addTimeId(Long timeId) {
        this.TIME_ID_SET.add(timeId);
    }

    public Set<Long> placeIdSet() {
        return PLACE_ID_SET;
    }

    public Long[] placeIdArr() {
        return PLACE_ID_SET.toArray(new Long[0]);
    }

    public Set<Long> timeIdSet() {
        return TIME_ID_SET;
    }

    public Long[] timeIdArr() {
        return TIME_ID_SET.toArray(new Long[0]);
    }

    public Map<String, ScoreExExamSession> sessionMap() {
        return this.SESSION_MAP;
    }
}
